package com.zhs.gccs.http;

import android.util.Log;

import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhs.gccs.BuildConfig;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Converter;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

public class Api {

    public static final int DEFAULT_TIMEOUT = 180;
    private static ApiService service;
    private static Call dlCall = null;
    private static Call upLoadCall = null;

    public static Call getDlCall() {
        return dlCall;
    }

    public static void setDlCall(Call dlCall) {
        Api.dlCall = dlCall;
    }

    public static Call getUpLoadCall() {
        return upLoadCall;
    }

    public static void setUpLoadCall(Call upLoadCall) {
        Api.upLoadCall = upLoadCall;
    }

    public static void download(String path, final File file, final CommonCallback.OnProgressCallBack onProgressCallBack) {
        Call<ResponseBody> call = getDefault().downloadFileByPath(path);
        setDlCall(call);
        Observable.create(new ObservableOnSubscribe<Response<ResponseBody>>() {
            @Override
            public void subscribe(final ObservableEmitter<Response<ResponseBody>> e) throws Exception {
                call.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, final retrofit2.Response<ResponseBody> response) {
                        e.onNext(response);
                    }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        t.printStackTrace();
                        onProgressCallBack.onFaile();
                    }
                });
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .subscribe(new Observer<Response<ResponseBody>>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(retrofit2.Response<ResponseBody> response) {
                        try {
                            if (response.isSuccessful()) {
//                        LogUtils.e("response.body() = " + response.body().string());
                                InputStream inputStream = null;
                                OutputStream outputStream = null;
                                try {
                                    byte[] fileReader = new byte[4096];
                                    float fileSize = response.body().contentLength();
                                    float fileSizeDownloaded = 0;
                                    inputStream = response.body().byteStream();
                                    outputStream = new FileOutputStream(file);
                                    while (true) {
                                        int read = inputStream.read(fileReader);
                                        if (read == -1) {
                                            break;
                                        }
                                        outputStream.write(fileReader, 0, read);
                                        fileSizeDownloaded += read;
                                        Log.e("sc", "fileSizeDownloaded = " + fileSizeDownloaded + ", fileSize = " + fileSize + ", p = " + (fileSizeDownloaded / fileSize));
                                        onProgressCallBack.onProgress(fileSizeDownloaded / fileSize);
                                    }
                                    outputStream.flush();
                                    onProgressCallBack.onDone(file);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    onProgressCallBack.onFaile();
                                } finally {
                                    if (inputStream != null) {
                                        inputStream.close();
                                    }
                                    if (outputStream != null) {
                                        outputStream.close();
                                    }
                                }

                            } else {
                                onProgressCallBack.onFaile();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                            onProgressCallBack.onFaile();
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        onProgressCallBack.onFaile();
                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }

    public static void uploadFeedback(String filePath, String filePartName, Map<String, Object> params,
                                      CommonCallback.OnMultiUploadCallBack callBack) {
        File file = new File(filePath);
        if (file.exists()) {
            Log.e("xp", "file = " + file.getAbsolutePath());
        }
        Log.e("xp", "上传path = " + filePath + ", size = " + file.length());
        String suffixName = "";
        if (file.getAbsoluteFile().toString().endsWith(".jpg") ||
                file.getAbsoluteFile().toString().endsWith(".png") ||
                file.getAbsoluteFile().toString().endsWith(".jpeg") ||
                file.getAbsoluteFile().toString().endsWith(".JPG") ||
                file.getAbsoluteFile().toString().endsWith(".PNG") ||
                file.getAbsoluteFile().toString().endsWith(".JPEG")) {
            suffixName = "image/jpeg";
        }
        else if (file.getAbsoluteFile().toString().endsWith(".png") ||
                file.getAbsoluteFile().toString().endsWith(".PNG")) {
            suffixName = "image/png";
        }
        else {
            suffixName = "multipart/form-data";
        }
        RequestBody requestFile = RequestBody.create(MediaType.parse(suffixName), file);
        MultipartBody.Part fileBody = null;
        RequestBodyUpload requestBodyUpload = new RequestBodyUpload(requestFile, file.getName(), new CommonCallback.OnProgressWithNameCallBack() {
            @Override
            public void onProgress(String filename, float percent) {
                callBack.onFileProgress(filename, percent);
                Log.e("xp", "filename = " + filename + ", percent = " + percent);
            }
        });
        fileBody = MultipartBody.Part.
                createFormData(filePartName, file.getName(), requestBodyUpload);
        //构造参数
        Map<String, RequestBody> _params = new HashMap<>();
        Iterator<Map.Entry<String, Object>> iterator = params.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"),
                    entry.getValue().toString());
            _params.put(entry.getKey(), requestBody);
        }
        Call<ResponseBody> call = Api.getDefault()
                .uploadFeedbackFile(_params,fileBody);
        setUpLoadCall(call);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
                try {
                    Log.e("xp", "请求成功 code = " + response.code());
                    String result = response.body().string();
                    Log.e("xp", "response.body() = " + result);
                    if (response.code() == 200) {
//                        UploadFile1Bean bean = JSON.parseObject(result, UploadFile1Bean.class);//GsonImpl.get().toObject(result, UploadFile1Bean.class);
//                        String msg;
//                        boolean isOK = false;
//                        if(bean.getCode()==200){
//                            msg = "反馈成功";
//                            isOK = true;
//                        }else {
//                            msg = "反馈出错";
//                            isOK = false;
//                        }
//                        EventBus.getDefault().post(new uploadMsgEvent(2,isOK,msg));
                        JSONObject data = JSON.parseObject(result);
                        int code = data.getIntValue("code");
                        if(code==200){
                            callBack.onDone("成功");
                        }else {
                            callBack.onFaile(null);
                        }
                    }else {
//                        EventBus.getDefault().post(new uploadMsgEvent(2,false,"服务器错误"));
                        callBack.onFaile(null);
                    }
                } catch (Exception e) {
                    callBack.onFaile(e);
                }
            }
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                callBack.onFaile(t);
            }
        });
    }

    public static ApiService getDefault() {
        if (service == null) {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.level(HttpLoggingInterceptor.Level.HEADERS);
            OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
            httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
            httpClientBuilder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
            httpClientBuilder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
            httpClientBuilder.addInterceptor(logging);
            httpClientBuilder.addInterceptor(new TokenInterceptor());
            OkHttpClient client = httpClientBuilder.build();
            service = new Retrofit.Builder()
                    .client(client)
                    .addConverterFactory(new ToStringConverterFactory())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .baseUrl(BuildConfig.BASEURL)
                    .build()
                    .create(ApiService.class);
        }
        return service;
    }

    public static class ToStringConverterFactory extends Converter.Factory {
        private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain");

        @Nullable
        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
            if (String.class.equals(type)) {
                return new Converter<ResponseBody, String>() {
                    @Override
                    public String convert(ResponseBody value) throws IOException {
                        return value.string();
                    }
                };
            }

            return null;
        }
        @Nullable
        @Override
        public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
            if (String.class.equals(type)) {
                return new Converter<String, RequestBody>() {
                    @Override
                    public RequestBody convert(String value) throws IOException {
                        return RequestBody.create(MEDIA_TYPE, value);
                    }
                };
            }
            return null;
        }
    }
}
